/*
 * sys_mem.c
 *
 *  Created on: 2017年8月5日
 *      Author: 0yfj0
 */

#include "sys_mem.h"

#include <string.h>

/*----------------------------------------------------------------------------*/
mem_t mem;

/*----------------------------------------------------------------------------*/
int mem_init(void *buff, uint32_t size)
{
	ptr_t addr;
	ptr_t align;

	if (!buff || !size)
		return (-1);

	addr = (ptr_t) buff;
	align = ((addr + 3) >> 2) << 2;/* 地址对齐 */
	size = size - (align - addr);/* size调整 */
	size = ((size + 3) >> 2) << 2;
	if (size < 4)
		return (-1);
	memset(&mem, 0, sizeof(mem_t));
	mem.addr = align;
	mem.size = size;
	mem.magic = MEM_MAGIC;
	mem_log("mem_init sucess\r\n");
	return (0);
}
void *mem_malloc(uint32_t size)
{
	int i;
	int bit0;
	uint32_t bits;
	uint32_t unused;
	uint32_t need;

	if (mem.magic != MEM_MAGIC)
		return (NULL);

	/* 分配策略-最先匹配 */
	need = (size + MEM_BIT_SIZE - 1) / MEM_BIT_SIZE + 2;
	bits = mem.size / MEM_BIT_SIZE;
	for (i = 0, unused = 0, bit0 = 0; i < bits; ++i)
	{
		if (mem_flag(i) == 0)
		{
			if (unused == 0)
				bit0 = i;
			++unused;
		}
		else
			unused = 0;

		if ((!bit0 && unused == need - 1) || (unused == need))
		{
			if (bit0 != 0)
				++bit0;
			need -= 2;
			for (i = bit0; i < bit0 + need; ++i)
				mem_flag_lock(i);/* lock memory */
			
			mem_log("mem_malloc @0x%X\r\n", mem.addr + bit0 * MEM_BIT_SIZE);
			return ((void*) (mem.addr + bit0 * MEM_BIT_SIZE));
		}
	}

	if (i == bits)
	{
		if ((bit0 == 0 && unused == need - 2) || (unused == need - 1))
		{
			if (bit0 != 0)
				++bit0;
			need -= 2;
			for (i = bit0; i < bit0 + need; ++i)
				mem_flag_lock(i);/* lock memory */
			
			mem_log("mem_malloc @0x%X\r\n", mem.addr + bit0 * MEM_BIT_SIZE);
			return ((void*) (mem.addr + bit0 * MEM_BIT_SIZE));
		}
	}
	
	mem_log("mem_malloc failed\r\n");
	return (NULL);
}
void *mem_calloc(uint32_t n, uint32_t size)
{
	void *heap = mem_malloc(n * size);

	if (heap)
	{
		memset(heap, 0, n * size);
		mem_log("mem_calloc @0x%X\r\n", (ptr_t) heap);
	}
	
	return (heap);
}
void *mem_realloc(void *buff, uint32_t newsize)
{
	int i;
	int bit0;
	uint32_t bits;
	ptr_t addr;
	uint32_t used;
	uint32_t need;
	void *heap;

	if (mem.magic != MEM_MAGIC)
		return (NULL);

	addr = (ptr_t) buff;
	if ((addr & 3) || addr < mem.addr)
		return (NULL);

	need = (newsize + MEM_BIT_SIZE - 1) / MEM_BIT_SIZE + 1;
	bit0 = (addr - mem.addr) / MEM_BIT_SIZE;
	if (bit0 != 0 && (mem_flag(bit0 - 1)) != 0)
	{
		mem_log("mem_realloc address illegal\r\n");
		return (NULL);/* 给定需要重新分配的地址不合法 */
	}
	if (mem_flag(bit0) == 0)
	{
		mem_log("mem_realloc address illegal\r\n");
		return (NULL);/* 给定需要重新分配的地址不合法 */
	}

	bits = mem.size / MEM_BIT_SIZE;
	for (i = bit0, used = 0; i < bits; ++i)
	{
		if (mem_flag(i) != 0)
			++used;
		else
			break;
	}

	if (used + 1 >= need)/* 重新分配变小 */
	{
		for (i = bit0 + need - 1; i < bits; ++i)
		{
			if (mem_flag(i) != 0)
				mem_flag_unlock(i);/* unlock memory */
			else
				break;
		}
		
		mem_log("mem_realloc realloc small @0x%X\r\n", (ptr_t) buff);
		return (buff);
	}
	else/* 重新分配变大 */
	{
		for (i = bit0 + used + 1; i < bits; ++i)
		{
			if (mem_flag(i) == 0)
			{
				if (i - bit0 == need)
				{
					for (i = bit0 + 1; i < bit0 + need - 1; ++i)
						mem_flag_lock(i);/* lock memory */
					
					mem_log("mem_realloc realloc big @0x%X\r\n", (ptr_t) buff);
					return (buff);
				}
			}
			else
				break;
		}

		if (i == bits && i - bit0 == need - 1)
		{
			for (i = bit0 + 1; i < bits; ++i)
				mem_flag_lock(i);/* lock memory */
			
			mem_log("mem_realloc realloc big @0x%X\r\n", (ptr_t) buff);
			return (buff);
		}
	}

	/* 重新分配变大失败，再次重新分配 */
	heap = mem_malloc(newsize);
	if (heap)
	{
		memcpy(heap, buff, used * MEM_BIT_SIZE);
		mem_log("mem_realloc realloc @0x%X\r\n", (ptr_t) heap);
		mem_free(buff);
	}
	else
	{
		mem_log("mem_realloc failed, no memory\r\n");
	}

	return (heap);
}
void mem_free(void *buff)
{
	int i;
	int bit0;
	uint32_t bits;
	ptr_t addr;

	if (mem.magic != MEM_MAGIC)
		return;

	addr = (ptr_t) buff;
	if ((addr & 3) || addr < mem.addr || addr > mem.addr + mem.size)
		return;

	bit0 = (addr - mem.addr) / MEM_BIT_SIZE;
	if (bit0 != 0 && mem_flag(bit0 - 1) != 0)
	{
		mem_log("mem_free address illegal\r\n");
		return;/* 不是合法的地址 */
	}
	if (mem_flag(bit0) == 0)
	{
		mem_log("mem_free address illegal\r\n");
		return;/* 不是合法的地址 */
	}

	bits = mem.size / MEM_BIT_SIZE;
	for (i = bit0; i < bits; ++i)
	{
		if (mem_flag(i) != 0)
			mem_flag_unlock(i);/* unlock memory */
		else
			break;
	}
	mem_log("mem_free @0x%X\r\n", addr);
}

#if (MEM_DBG)
#include <stdarg.h>
void mem_log(char *format, ...)
{
    va_list args;

    /* args point to the first variable parameter */
    va_start(args, format);
    MEM_LOG(format, args);
    va_end(args);
    MEM_FFLUSH();
}
#endif

/*----------------------------------------------------------------------------*/
#if (MEM_FUNC_TEST)
void mem_test(void)
{
	void *heap;
	void *heap0;
	void *heap1;
	void *heap2;
	void *heap3;

	heap = mem_malloc(1);
	heap = mem_realloc(heap, 2);
	heap = mem_realloc(heap, 5);
	heap = mem_realloc(heap, 7);
	heap = mem_realloc(heap, 8);
	heap = mem_realloc(heap, 32);
	heap = mem_realloc(heap, 64);
	heap = mem_realloc(heap, 32);
	heap = mem_realloc(heap, 8);
	heap = mem_realloc(heap, 5);
	mem_free(heap);

	heap0 = mem_malloc(8);
	heap1 = mem_malloc(32);
	heap2 = mem_malloc(2048);
	heap3 = mem_malloc(8);
	mem_free(heap0);
	heap0 = mem_malloc(16);
	mem_free(heap1);
	heap1 = mem_malloc(32);
	mem_free(heap2);
	mem_free(heap3);
	mem_free(heap0);
	mem_free(heap1);

	heap = mem_malloc(mem.size);
	heap = mem_realloc(heap, 1);
	heap = mem_realloc(heap, 128);
	heap = mem_realloc(heap, mem.size);
	mem_free(heap);

	heap = mem_malloc(1);
	heap = mem_realloc(heap, 16);
	heap = mem_realloc(heap, 128);
	heap = mem_realloc(heap, mem.size);
	heap = mem_realloc(heap, 512);
	mem_free(heap);
}
#endif

/*----------------------------------------------------------------------------*/
